#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2021/4/26 14:22
# @Author  : LiShan
# @Email   : lishan_1997@126.com
# @File    : window.py
# @Note    : this is note
import os
import time
import matplotlib.pyplot as plt
import numpy as np

from multiprocessing import Process, Queue
from winreg import OpenKey, QueryValueEx, HKEY_CURRENT_USER
from PyQt5.QtGui import QIcon, QPixmap, QTextCursor
from PyQt5.QtWidgets import QMainWindow, QFileDialog, QApplication
from PyQt5.uic import loadUiType

import simulation.simulation
from interface import aboutDialog, contact
from simulation import simulation


def get_desktop_path():
    key = OpenKey(HKEY_CURRENT_USER, r'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders')
    return QueryValueEx(key, "Desktop")[0]


ui, _ = loadUiType("./resource/ui/window.ui")


# 主窗口界面
class MainWindow(QMainWindow, ui):
    def __init__(self):
        QMainWindow.__init__(self)
        self.setupUi(self)
        self.resize(1366, 700)
        self.setWindowTitle("基于Vissim-Python的信控交叉口仿真评估平台 SISEP-VP 1.0")
        self.setWindowIcon(QIcon("./resource/icon/app.png"))
        # 隐藏tab标签
        self.tabWidget.tabBar().setVisible(False)
        # 类属性
        self.program_path = get_desktop_path().replace("\\", "/") + "/vissim.lnk"
        self.net_path = os.getcwd().replace("\\", "/") + "/resource/vissim/3.inp"
        self.flow_path = os.getcwd().replace("\\", "/") + "/resource/data/vehicle_inputs.txt"
        self.save_path = os.getcwd().replace("\\", "/") + "/resource/save/"
        self.sim_step = 5
        self.vehicle = []
        self.num = 0
        self.simulation = [999999, 0, 1, 1, 42, False, False]
        self.timming = [24, 38, 2, 130, 20, 3, [2, 2, 2, 2]]
        # 实例化类
        self.versionDialog = aboutDialog.versionDialog()
        self.contactDialog = contact.contactDialog()
        self.sim = simulation.Sim()
        # 让图片自适应label大小
        self.label_net.setScaledContents(True)
        self.label_alg.setScaledContents(True)
        self.label_sim.setScaledContents(True)
        self.label_eval.setScaledContents(True)
        # 设置图标
        self.label_net.setPixmap(QPixmap("./resource/icon/net.png"))
        self.label_alg.setPixmap(QPixmap("./resource/icon/algorithm.png"))
        self.label_sim.setPixmap(QPixmap("./resource/icon/simulation.png"))
        self.label_eval.setPixmap(QPixmap("./resource/icon/evaluate.png"))
        # 主界面界面切换槽函数
        self.pushButton1.clicked.connect(self.switch_to_net_panel)
        self.pushButton2.clicked.connect(self.switch_to_algorithm_panel)
        self.pushButton3.clicked.connect(self.switch_to_simulation_panel)
        self.pushButton4.clicked.connect(self.switch_to_evaluate_panel)
        # 菜单栏触发信号
        self.action_import.triggered.connect(self.contactDialog.show)
        self.action_export.triggered.connect(self.contactDialog.show)
        self.action_local.triggered.connect(self.contactDialog.show)
        self.action_online.triggered.connect(self.contactDialog.show)
        self.action_version.triggered.connect(self.versionDialog.show)
        self.action_contact.triggered.connect(self.contactDialog.show)
        # 路网界面按钮槽连接
        self.pushButton_load.clicked.connect(self.load_net_file)
        self.pushButton_parse.clicked.connect(self.load_net_file)
        self.pushButton_edit.clicked.connect(self.load_net_file)
        self.pushButton_update.clicked.connect(self.load_net_file)
        self.pushButton_save.clicked.connect(self.load_net_file)
        # 仿真界面按钮槽连接
        self.pushButton_program_path.clicked.connect(self.load_program_path)
        self.pushButton_net_path.clicked.connect(self.load_net_path)
        self.pushButton_flow_path.clicked.connect(self.load_flow_path)
        self.pushButton_save_path.clicked.connect(self.load_save_path)
        self.pushButton_simulation.clicked.connect(self.run_simulation)
        # 自定义信号
        self.sim.PrintInfoEmit.connect(self.update_simulation_textBrowser)
        self.sim.TimeInfoEmit.connect(self.update_label_remain_time)
        # 初始化仿真设置
        self.lineEdit_sim_path.setText(self.program_path)
        self.lineEdit_net_path.setText(self.net_path)
        self.lineEdit_flow_path.setText(self.flow_path)
        self.lineEdit_save_path.setText(self.save_path)
        # 默认显示路网界面
        self.switch_to_net_panel()

    # 切换到路网界面
    def switch_to_net_panel(self):
        self.tabWidget.setCurrentIndex(0)
        self.statusBar().showMessage("路网界面")

    # 切换到算法界面
    def switch_to_algorithm_panel(self):
        self.tabWidget.setCurrentIndex(1)
        self.statusBar().showMessage("算法界面")

    # 切换到仿真界面·
    def switch_to_simulation_panel(self):
        self.tabWidget.setCurrentIndex(2)
        self.statusBar().showMessage("仿真界面")

    # 切换到评价界面
    def switch_to_evaluate_panel(self):
        self.tabWidget.setCurrentIndex(3)
        self.statusBar().showMessage("评价界面")

    """路网界面"""

    # 加载路网文件
    def load_net_file(self):
        reply = QFileDialog.getOpenFileName(self, "道路仿真路网文件", "./resource/", "(*.inp *.ini)")
        try:
            if reply[0]:
                self.net_path = reply[0]
                with open(self.net_path, "r") as f:
                    content = f.readlines()
                self.textBrowser_net_info.clear()
                for i in range(len(content)):
                    self.textBrowser_net_info.append(content[i])
                self.textBrowser_net_info.moveCursor(QTextCursor.Start)
        except (IndexError, Exception):
            pass

    """算法界面"""

    # 加载仿真软件路径
    def load_program_path(self):
        reply = QFileDialog.getOpenFileName(self, "加载vissim启动文件", get_desktop_path(), "(*.exe *.lnk)")
        try:
            if reply[0]:
                self.program_path = reply[0]
                self.lineEdit_sim_path.setText(self.program_path)
        except (IndexError, Exception):
            pass

    # 加载路网文件路径
    def load_net_path(self):
        reply = QFileDialog.getOpenFileName(self, "道路仿真路网文件", "./", "(*.inp *.ini)")
        try:
            if reply[0]:
                self.net_path = reply[0]
                self.lineEdit_net_path.setText(self.net_path)
        except (IndexError, Exception):
            pass

    # 加载交通流量文件路径
    def load_flow_path(self):
        reply = QFileDialog.getOpenFileName(self, "交通流量文件", "./", "(*.txt *.xlsx *.xls)")
        try:
            if reply[0]:
                self.flow_path = reply[0]
                self.lineEdit_flow_path.setText(self.flow_path)
        except (IndexError, Exception):
            pass

    # 加载评价保存路径
    def load_save_path(self):
        reply = QFileDialog.getExistingDirectory(self, "仿真结果保存路径", "./")
        try:
            if reply[0]:
                self.save_path = reply
                self.lineEdit_save_path.setText(self.save_path)
        except (IndexError, Exception):
            pass

    """仿真信息界面"""

    # 加载仿真参数设置
    def load_simulation_setting(self):
        period = int(self.lineEdit_Sim_Period.text())
        speed = int(self.lineEdit_Sim_speed.text())
        resolution = int(self.lineEdit_Sim_resolution.text())
        control_freq = int(self.lineEdit_Control_Freq.text())
        seed = int(self.lineEdit_Random_Seed.text())
        if self.radioButton_hidden_flow.isChecked():
            visualization = False
        else:
            visualization = True
        if self.radioButton_3D_mode.isChecked():
            mode = True
        else:
            mode = False
        setting = [period, speed, resolution, control_freq, seed, visualization, mode]
        return setting

    # 加载车流量
    def load_traffic_flow(self, elapsed_time):
        while True:
            if elapsed_time < self.vehicle[self.num][1]:
                break
            else:
                self.num += 1
        return self.vehicle[self.num][2:]

    # 加载车流量配置文件
    def load_traffic_flow_file(self):
        with open(self.flow_path, "r") as f:
            lines = f.readlines()
        self.vehicle = []
        self.num = 0
        for i in range(1, len(lines)):
            self.vehicle.append(list(map(int, lines[i].split())))

    # 显示提示信息
    def show_hint_information(self):
        self.textBrowser_sim_info.clear()
        self.textBrowser_sim_info.append("Real-time simulation information:\n")
        self.textBrowser_sim_info.append("%-4s  %-8s  %-5s  %-32s  %-56s  %-52s  %-9s" %
                                         ("step", "time", "sim", "flow", "speed", "queue", "delay"))
        self.textBrowser_sim_info.append("*" * 178 + '\n')

    # 刷新仿真信息文本浏览框
    def update_simulation_textBrowser(self, info):
        QApplication.processEvents()
        self.textBrowser_sim_info.append(info)

    # 刷新剩余时间信息
    def update_label_remain_time(self, info):
        QApplication.processEvents()
        self.label_remain_time.setText("预计离仿真结束还有%02d时%02d分%02d秒")

    # 保存仿真数据记录
    def save_simulation_data(self):
        # 保存为txt文件
        name = time.strftime("%Y-%m-%d-%H-%M-%S") + ".txt"
        path = "./resource/tmp/record/" + name
        with open(path, "w") as f:
            f.write(self.textBrowser_sim_info.toPlainText())
        # 绘制延误曲线
        delay = []
        legend = ["delay"]
        with open(path, "r") as f:
            lines = f.readlines()
        for i in range(4 + 5, len(lines)):
            line = lines[i].split()[-1][1:-1]
            delay.append(float(line))
        # 绘图
        x = np.linspace(0, len(delay), len(delay))
        plt.plot(x, delay)
        # 设置坐标轴名称
        plt.xlabel("Step", fontproperties='Times New Roman', size=10.5)
        plt.ylabel("delay", fontproperties='Times New Roman', size=10.5)
        # 设置网格
        plt.grid()
        # 设置图例
        plt.legend(legend, loc="lower right", frameon=False)
        # 设置标题
        plt.title("Average delay variation", fontproperties='SimSun', size=10.5)
        # 保存图片
        plt.savefig("delay.svg")

    # 运行仿真
    def run_simulation(self):
        # 显示提示信息
        self.show_hint_information()
        # 加载车流量配置文件
        self.load_traffic_flow_file()
        # 初始化仿真
        self.sim.run(self.net_path, self.simulation, self.timming)

